// Copyright(C) 2023 InfiniFlow, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

export module infinity_core:physical_alter;

import :query_context;
import :operator_state;
import :physical_operator;
import :physical_operator_type;
import :load_meta;
import :infinity_exception;
import :logger;
import :meta_info;

import internal_types;
import data_type;
import alter_statement;
import column_def;
import constant_expr;

namespace infinity {

export class PhysicalAlter : public PhysicalOperator {
public:
    explicit PhysicalAlter(const std::shared_ptr<TableInfo> &table_info,
                           AlterStatementType type,
                           std::shared_ptr<std::vector<std::string>> output_names,
                           std::shared_ptr<std::vector<std::shared_ptr<DataType>>> output_types,
                           u64 id,
                           std::shared_ptr<std::vector<LoadMeta>> load_metas)
        : PhysicalOperator(PhysicalOperatorType::kAlter, nullptr, nullptr, id, load_metas), table_info_(table_info),
          output_names_(std::move(output_names)), output_types_(std::move(output_types)) {}

    ~PhysicalAlter() override = default;

    inline std::shared_ptr<std::vector<std::string>> GetOutputNames() const final { return output_names_; }

    inline std::shared_ptr<std::vector<std::shared_ptr<DataType>>> GetOutputTypes() const final { return output_types_; }

protected:
    AlterStatementType type_;
    std::shared_ptr<TableInfo> table_info_{};
    std::shared_ptr<std::vector<std::string>> output_names_{};
    std::shared_ptr<std::vector<std::shared_ptr<DataType>>> output_types_{};
};

export class PhysicalRenameTable final : public PhysicalAlter {
public:
    PhysicalRenameTable(const std::shared_ptr<TableInfo> &table_info,
                        std::string &&new_table_name,
                        std::shared_ptr<std::vector<std::string>> output_names,
                        std::shared_ptr<std::vector<std::shared_ptr<DataType>>> output_types,
                        u64 id,
                        std::shared_ptr<std::vector<LoadMeta>> load_metas)
        : PhysicalAlter(table_info, AlterStatementType::kRenameTable, std::move(output_names), std::move(output_types), id, load_metas),
          new_table_name_(std::move(new_table_name)) {}

    void Init(QueryContext *query_context) override;

    bool Execute(QueryContext *query_context, OperatorState *operator_state) override;

private:
    std::string new_table_name_;
};

export class PhysicalAddColumns final : public PhysicalAlter {
public:
    PhysicalAddColumns(const std::shared_ptr<TableInfo> &table_info,
                       const std::vector<std::shared_ptr<ColumnDef>> &column_defs,
                       std::shared_ptr<std::vector<std::string>> output_names,
                       std::shared_ptr<std::vector<std::shared_ptr<DataType>>> output_types,
                       u64 id,
                       std::shared_ptr<std::vector<LoadMeta>> load_metas)
        : PhysicalAlter(table_info, AlterStatementType::kAddColumns, std::move(output_names), std::move(output_types), id, load_metas),
          column_defs_(column_defs) {}

    void Init(QueryContext *query_context) override;

    bool Execute(QueryContext *query_context, OperatorState *operator_state) override;

private:
    const std::vector<std::shared_ptr<ColumnDef>> &column_defs_;
};

export class PhysicalDropColumns final : public PhysicalAlter {
public:
    PhysicalDropColumns(const std::shared_ptr<TableInfo> &table_info,
                        const std::vector<std::string> &column_names,
                        std::shared_ptr<std::vector<std::string>> output_names,
                        std::shared_ptr<std::vector<std::shared_ptr<DataType>>> output_types,
                        u64 id,
                        std::shared_ptr<std::vector<LoadMeta>> load_metas)
        : PhysicalAlter(table_info, AlterStatementType::kDropColumns, std::move(output_names), std::move(output_types), id, load_metas),
          column_names_(column_names) {}

    void Init(QueryContext *query_context) override;

    bool Execute(QueryContext *query_context, OperatorState *operator_state) override;

private:
    const std::vector<std::string> &column_names_;
};

export class PhysicalAlterIndex final : public PhysicalAlter {
public:
    PhysicalAlterIndex(const std::shared_ptr<TableInfo> &table_info,
                       std::string index_name,
                       std::vector<std::unique_ptr<InitParameter>> opt_params,
                       std::shared_ptr<std::vector<std::string>> output_names,
                       std::shared_ptr<std::vector<std::shared_ptr<DataType>>> output_types,
                       u64 id,
                       std::shared_ptr<std::vector<LoadMeta>> load_metas)
        : PhysicalAlter(table_info, AlterStatementType::kAlterIndex, std::move(output_names), std::move(output_types), id, load_metas),
          index_name_(std::move(index_name)), opt_params_(std::move(opt_params)) {}

    ~PhysicalAlterIndex() override = default;

    void Init(QueryContext *query_context) override;

    bool Execute(QueryContext *query_context, OperatorState *operator_state) override;

private:
    std::string index_name_{};
    std::vector<std::unique_ptr<InitParameter>> opt_params_;
};

} // namespace infinity
